/*
 * Copyright 2009 BioTeam Inc
 * 
 * Licensed under License GNU LESSER GENERAL PUBLIC LICENSE version 3.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.bioteam.appweb.gwt.apps.server.data;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import net.bioteam.appweb.gwt.apps.clientandserver.ServerException;
import net.bioteam.appweb.gwt.apps.clientandserver.datatree.FileNode;
import net.bioteam.appweb.gwt.apps.clientandserver.datatree.FileNodes;
import net.bioteam.appweb.gwt.apps.server.MyRemoteServiceServlet;
import net.bioteam.appweb.gwt.apps.server.UnsupportedUserFileTypeException;
import net.bioteam.appweb.gwt.apps.server.UserFileConverter;
import net.bioteam.common.user.User;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class FileNodesImpl extends MyRemoteServiceServlet implements FileNodes
{
	public static final Log logger = LogFactory.getLog(FileNodesImpl.class);

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public FileNode copyFile(String oldPath, String newPath) throws ServerException
	{
		User user = (User) getThreadLocalRequest().getSession().getAttribute("user");
		String username = user.getName();
		File srcFile = null;
		File destFile = null;
		if (user.isAdmin())
			try
			{
				srcFile = new File(UserFileConverter.clientPathToRealPath(oldPath, username));
				destFile = new File(UserFileConverter.clientPathToRealPath(newPath, username));
			} catch (UnsupportedUserFileTypeException e1)
			{
				throw new ServerException(e1.getMessage());
			}
		else
		{
			// user can only edit his own data file.
			srcFile = new File(UserFileConverter.dataClientPathToRealPath(oldPath, username));
			destFile = new File(UserFileConverter.dataClientPathToRealPath(newPath, username));
		}
		if (!srcFile.exists())
		{
			throw new ServerException("Can not find source file:"+srcFile.getName());
		}
		if (destFile.exists())
		{
			throw new ServerException("Destination file "+destFile.getName()+" already exists");
		}
		if (srcFile.isDirectory())
		{
			try
			{
				FileUtils.copyDirectory(srcFile, destFile);
				return getFileNode(destFile, username);
			} catch (Exception e)
			{
				throw new ServerException(e.getMessage());
			}
		} else
		{
			try
			{
				FileUtils.copyFile(srcFile, destFile);
				return getFileNode(destFile, username);
			} catch (Exception e)
			{
				throw new ServerException(e.getMessage());
			}
		}
	}

	public String deleteFile(String path) throws ServerException
	{
		User user = (User) getThreadLocalRequest().getSession().getAttribute("user");
		String username = user.getName();
		// only data file can be deleted. So
		File srcFile = null;
		if (user.isAdmin())
			try
			{
				srcFile = new File(UserFileConverter.clientPathToRealPath(path, username));
			} catch (UnsupportedUserFileTypeException e1)
			{
				throw new ServerException(e1.getMessage());
			}
		else
			// user can only edit his own data file.
			srcFile = new File(UserFileConverter.dataClientPathToRealPath(path, username));
		if (!srcFile.exists())
		{
			throw new ServerException("Can not find file");
		}
		if (srcFile.isFile())
		{
			if (!srcFile.delete())
			{
				throw new ServerException("fail to delete file");
			}
		} else
		{
			try
			{
				FileUtils.deleteDirectory(srcFile);
			} catch (IOException e)
			{
				throw new ServerException("fail to delete file");
			}
		}
		return "File is deleted successfully";

	}

	public FileNode makeDir(String newDir) throws ServerException
	{
		User user = (User) getThreadLocalRequest().getSession().getAttribute("user");
		String username = user.getName();
		File srcFile = null;
		if (user.isAdmin())
			try
			{
				srcFile = new File(UserFileConverter.clientPathToRealPath(newDir, username));
			} catch (UnsupportedUserFileTypeException e1)
			{
				throw new ServerException(e1.getMessage());
			}
		else
		{
			// user can only edit his own data file.
			srcFile = new File(UserFileConverter.dataClientPathToRealPath(newDir, username));
		}
		if (srcFile.exists())
		{
			throw new ServerException(" fail to make directory "+srcFile.getName()+": already exist");
		}
		if (!srcFile.mkdirs())
		{
			throw new ServerException("fail to make directory");
		}
		try
		{
			return getFileNode(srcFile, username);
		} catch (UnsupportedUserFileTypeException e)
		{
			throw new ServerException(e.getMessage());
		}
	}

	public FileNode moveFile(String oldPath, String newPath) throws ServerException
	{
		User user = (User) getThreadLocalRequest().getSession().getAttribute("user");
		String username = user.getName();
		File srcFile = null;
		File destFile = null;
		if (user.isAdmin())
			try
			{
				srcFile = new File(UserFileConverter.clientPathToRealPath(oldPath, username));
				destFile = new File(UserFileConverter.clientPathToRealPath(newPath, username));
			} catch (UnsupportedUserFileTypeException e1)
			{
				throw new ServerException(e1.getMessage());
			}
		else
		{
			// user can only edit his own data file.
			srcFile = new File(UserFileConverter.dataClientPathToRealPath(oldPath, username));
			destFile = new File(UserFileConverter.dataClientPathToRealPath(newPath, username));
		}
		if (!srcFile.exists())
		{
			throw new ServerException("Can not find source file/directory");
		}
		if (UserFileConverter.isJobFile(oldPath))
		{
			// copy action
			if (srcFile.isDirectory())
			{
				try
				{
					FileUtils.copyDirectory(srcFile, destFile);
					return getFileNode(destFile, username);
				} catch (Exception e)
				{
					throw new ServerException(e.getMessage());
				}
			} else
			{
				try
				{
					FileUtils.copyFile(srcFile, destFile);
					return getFileNode(destFile, username);
				} catch (Exception e)
				{
					throw new ServerException(e.getMessage());
				}
			}
		} else
		{
			try
			{
				FileUtils.moveFile(srcFile, destFile);
				return getFileNode(destFile, username);
			} catch (Exception e)
			{
				logger.warn(e.getMessage());
				throw new ServerException("Can not move source file/directory");
			}
		}
		
	}

	public FileNode renameFile(String oldPath, String newPath) throws ServerException
	{
		User user = (User) getThreadLocalRequest().getSession().getAttribute("user");
		String username = user.getName();
		// only data file can be deleted. So
		File srcFile = null;
		File destFile = null;
		if (user.isAdmin())
			try
			{
				srcFile = new File(UserFileConverter.clientPathToRealPath(oldPath, username));
				destFile = new File(UserFileConverter.clientPathToRealPath(newPath, username));
			} catch (UnsupportedUserFileTypeException e1)
			{
				throw new ServerException(e1.getMessage());
			}
		else
		{
			// user can only edit his own data file.
			srcFile = new File(UserFileConverter.dataClientPathToRealPath(oldPath, username));
			destFile = new File(UserFileConverter.dataClientPathToRealPath(newPath, username));
		}

		if (!srcFile.exists())
		{
			throw new ServerException("Can not find source file/directory");
		}
		if (srcFile.isFile())
		{
			try
			{
				FileUtils.moveFile(srcFile, destFile);
				return getFileNode(destFile, username);
			} catch (Exception e)
			{
				logger.warn(e.getMessage());

				throw new ServerException("Can not rename source file/directory");
			}
		} else
		{
			try
			{
				FileUtils.moveDirectory(srcFile, destFile);
				return getFileNode(destFile, username);
			} catch (Exception e)
			{
				logger.warn(e.getMessage());

				throw new ServerException("Can not rename source file/directory");
			}
		}

		
	}

	public FileNode[] getChildren(String parentPath) throws ServerException
	{
		try
		{
			String username = (String) getThreadLocalRequest().getSession().getAttribute("username");
			logger.info("get children for path"+parentPath);
			String filePath = UserFileConverter.clientPathToRealPath(parentPath, username);
			File dir = new File(filePath);
			if (!dir.exists())
				dir.mkdir();

			List<FileNode> nodes = new LinkedList<FileNode>();
			for (File child : dir.listFiles())
			{
				if (child.isFile())
				{
					continue;
				}
				nodes.add(getFileNode(child, username));
			}
			for (File child : dir.listFiles())
			{
				if (child.isDirectory())
				{
					continue;
				}
				
				nodes.add(getFileNode(child, username));
			}
			return nodes.toArray(new FileNode[0]);
		} catch (Exception e)
		{
			logger.warn("jobfile exception", e);
			throw new ServerException(e.getMessage());
		}

	}
	
	
	private FileNode getFileNode(File dir, String username) throws UnsupportedUserFileTypeException
	{
		if (dir.isDirectory())
		{
			String childpath = dir.getAbsolutePath();
			String clientPath = FilenameUtils.separatorsToUnix(UserFileConverter.realPathToClientPath(childpath, username));
			
			FileNode node=new FileNode(dir.getName(), false, getThreadLocalRequest().getContextPath() + "/apps/user/content" + clientPath);
			return node;
			//return new FileNode(dir.getName(), false);
		} else
		{
			String childpath = dir.getAbsolutePath();
			String clientPath = FilenameUtils.separatorsToUnix(UserFileConverter.realPathToClientPath(childpath, username));
			
			//return new FileNode(dir.getName(), true, "content" + clientPath);
			FileNode node=new FileNode(dir.getName(), true, getThreadLocalRequest().getContextPath() + "/apps/user/content" + clientPath);
			node.size=dir.length();
			return node;
			
		}
	}
}
